package net.yvesd.cellhunter.model.coverage;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.yvesd.cellhunter.model.Cell;
import net.yvesd.cellhunter.model.filter.LocationZeroAccuracyFilter;
import net.yvesd.cellhunter.model.filter.LocationUnknownAccuracyFilter;
import net.yvesd.cellhunter.model.filter.MaxCidFilter;
import net.yvesd.cellhunter.model.filter.MaxLacFilter;
import net.yvesd.cellhunter.model.filter.MetaFilter;
import net.yvesd.cellhunter.model.filter.UnknownRssiFilter;
import net.yvesd.cellhunter.model.filter.ZeroCidFilter;
import net.yvesd.cellhunter.model.filter.ZeroLacFilter;
import net.yvesd.cellhunter.persistance.CellHunterDbOpenHelper;
import android.content.Context;

public class MapCoverage {

	private Map<Cell, CellCoverage> coverageMap;
	private Context context;

	public MapCoverage(Context context) {
		this.context = context;

		coverageMap = new HashMap<Cell, CellCoverage>();
	}

	/**
	 * Adds one signal mesurement
	 * 
	 * @param lac
	 *            The LAC
	 * @param cid
	 *            The CID
	 * @param signalStrenghLocation
	 *            The new signal strength info to add
	 */
	public void addSignalMesurement(int lac, int cid,
			SignalStrengthLocation signalStrenghLocation) {

		List<SignalStrengthLocation> list = new ArrayList<SignalStrengthLocation>();
		list.add(signalStrenghLocation);

		MetaFilter filter = new MetaFilter();
		filter.add(new LocationUnknownAccuracyFilter());
		filter.add(new LocationZeroAccuracyFilter());
		filter.add(new ZeroLacFilter());
		filter.add(new ZeroCidFilter());
		filter.add(new MaxLacFilter());
		filter.add(new MaxCidFilter());
		filter.add(new UnknownRssiFilter());

		list = filter.filter(lac, cid, list);

		if (list.size() == 0)
			return;
		else
			signalStrenghLocation = list.get(0);

		CellCoverage cellCoverage = null;

		if (isCellKnown(lac, cid)) {
			cellCoverage = coverageMap.get(new Cell(lac, cid));
		} else {
			Cell c = new Cell(lac, cid);
			CellHunterDbOpenHelper.insertCell(context, c);
			putNewCellCoverage(c);
			cellCoverage = coverageMap.get(c);
		}

		boolean replaces = false;
		boolean overlaps = false;

		// Keep only the most precise locations
		Iterator<SignalStrengthLocation> itSignalStrengh;
		itSignalStrengh = cellCoverage.getSignalStrenghLocations().iterator();

		while (itSignalStrengh.hasNext()) {
			SignalStrengthLocation testedLoc = itSignalStrengh.next();

			if (signalStrenghLocation.isOverlappingWith(testedLoc)) {
				// Locations overlap
				overlaps = true;

				if (signalStrenghLocation.isMoreAccurateThan(testedLoc)) {
					// The location replaces another

					itSignalStrengh.remove();
					CellHunterDbOpenHelper
							.deleteSSL(context, testedLoc.getId());

					replaces = true;
				}
			}
		}

		if (!(overlaps) || overlaps && replaces) {
			cellCoverage.getSignalStrenghLocations().add(signalStrenghLocation);

			long id = CellHunterDbOpenHelper.insertSSL(context, lac, cid,
					signalStrenghLocation);
			signalStrenghLocation.setId(id);
		}
	}

	public int getKnownCellsCount() {
		return coverageMap.size();
	}

	public void putNewCellCoverage(Cell cell) {
		coverageMap.put(cell, new CellCoverage(cell));
	}

	public CellCoverage getCellCoverage(int lac, int cid) {
		return coverageMap.get(new Cell(lac, cid));
	}

	public Map<Cell, Integer> getStatistics() {
		Map<Cell, Integer> statistics = new HashMap<Cell, Integer>();

		for (Map.Entry<Cell, CellCoverage> e : coverageMap.entrySet()) {

			statistics.put(e.getKey(), e.getValue().getNumberOfMesurements());
		}

		return statistics;
	}

	public Set<Cell> getCells() {
		return coverageMap.keySet();
	}

	public boolean isCellKnown(int lac, int cid) {

		Cell cell = new Cell(lac, cid);

		return coverageMap.keySet().contains(cell);
	}

	public void deleteCell(int lac, int cid) {

		CellCoverage c = getCellCoverage(lac, cid);

		if (c != null)
			coverageMap.remove(new Cell(lac, cid));

		CellHunterDbOpenHelper.deleteCell(context, lac, cid);
		CellHunterDbOpenHelper.deleteSSLByCell(context, lac, cid);
	}
}
